/**
 *  @file bsp_irq_asm.S
 *
 *  Intererrupt handler for GameBoy Advance.
 */
/*
 *  RTEMS GBA BSP
 *
 *  Copyright (c) 2004  Markku Puro <markku.puro@kopteri.net>
 *
 *  The license and distribution terms for this file may be
 *  found in found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  $Id: bsp_irq_asm.S,v 1.1 2005/07/06 18:46:04 joel Exp $
 */

#define   __asm__
#include  <asm_macros.h>
#include  <gba_registers.h>
#include  <arm_mode_bits.h>
/* @cond  INCLUDE_ASM */

/**
 *  Execute interrupt handler
 *  function void ExecuteITHandler(void)
 *
 * Look at interrupt status register to determine source.
 * From source, determine offset into expanded vector table
 * and load handler address into r0.
 * irq_vector_table is defined in linkcmds
 *
 */
    .align
/*  .section  .iwram  */

PUBLIC_ARM_FUNCTION(ExecuteITHandler)
  ldr   r1, =GBA_REG_IE_ADDR
  ldrh  r1, [r1]
  ldr   r2, =GBA_REG_IF_ADDR
  ldrh  r2, [r2]
  and   r3, r1, r2  /* only look at interrupts which are enabled */

check_lcdv:
  tst   r3, #0x0001
  beq   check_lcdh
  ldr   r0, =(irq_vector_table + (4 * 0)) /* load the vector number */
  ldr   r3,=0x0001
  b     get_handler

check_lcdh:
  tst   r3, #0x0002
  beq   check_lcdvc
  ldr   r0, =(irq_vector_table + (4 * 1)) /* load the vector number */
  ldr   r3,=0x0002
  b     get_handler

check_lcdvc:
  tst   r3, #0x0004
  beq   check_t0
  ldr   r0, =(irq_vector_table + (4 * 2)) /* load the vector number */
  ldr   r3,=0x0004
  b     get_handler

check_t0:
  tst   r3, #0x0008
  beq   check_t1
  ldr   r0, =(irq_vector_table + (4 * 3)) /* load the vector number */
  ldr   r3,=0x0008
  b     get_handler

check_t1:
  tst   r3, #0x0010
  beq   check_t2
  ldr   r0, =(irq_vector_table + (4 * 4)) /* load the vector number */
  ldr   r3,=0x0010
  b     get_handler

check_t2:
  tst   r3, #0x0020
  beq   check_t3
  ldr   r0, =(irq_vector_table + (4 * 5)) /* load the vector number */
  ldr   r3,=0x0020
  b     get_handler

check_t3:
  tst   r3, #0x0040
  beq   check_ser
  ldr   r0, =(irq_vector_table + (4 * 6)) /* load the vector number */
  ldr   r3,=0x0040
  b     get_handler

check_ser:
  tst   r3, #0x0080
  beq   check_dma0
  ldr   r0, =(irq_vector_table + (4 * 7)) /* load the vector number */
  ldr   r3,=0x0080
  b     get_handler

check_dma0:
  tst   r3, #0x0100
  beq   check_dma1
  ldr   r0, =(irq_vector_table + (4 * 8)) /* load the vector number */
  ldr   r3,=0x0100
  b     get_handler

check_dma1:
  tst   r3, #0x0200
  beq   check_dma2
  ldr   r0, =(irq_vector_table + (4 * 9)) /* load the vector number */
  ldr   r3,=0x0200
  b     get_handler

check_dma2:
  tst   r3, #0x0400
  beq   check_dma3
  ldr   r0, =(irq_vector_table + (4 * 10)) /* load the vector number */
  ldr   r3,=0x0400
  b     get_handler

check_dma3:
  tst   r3, #0x0800
  beq   check_keypad
  ldr   r0, =(irq_vector_table + (4 * 11)) /* load the vector number */
  ldr   r3,=0x0800
  b     get_handler

check_keypad:
  tst   r3, #0x1000
  beq   check_gamepak
  ldr   r0, =(irq_vector_table + (4 * 12)) /* load the vector number */
  ldr   r3,=0x1000
  b     get_handler

check_gamepak:
  tst   r3, #0x2000
  beq   IRQ_NoInterrupt
  ldr   r0, =(irq_vector_table + (4 * 13)) /* load the vector number */
  ldr   r3,=0x2000
  b     get_handler

unknown_irq:
  ldr   r0, =(default_int_handler)          /* Unknown Interrupt?    */
  ldr   r3,=0x0000

get_handler:
  ldr   r0, [r0]             /* extract the IT handler */

  ldr   r2, =GBA_REG_IF_ADDR /* Clear IF               */
  strh  r3, [r2]

  /*
   * re-enable interrupts at processor level
   */
  mrs	r1, cpsr
  bic	r1, r1, #Int_Bits
  msr	cpsr, r1

  stmdb sp!,{lr}
  ldr   lr, =IRQ_return    /* prepare the return from handler  */
  mov   pc, r0             /* EXECUTE INT HANDLER */

IRQ_return:
  ldmia sp!,{lr}

  /*
   * disable interrupts_again
   */
  mrs	r0, cpsr
  orr	r0, r0, #Int_Bits
  msr	cpsr, r0

IRQ_NoInterrupt:
  /* return to the "main" interrupt handler */
  mov pc, lr

LABEL_END(ExecuteITHandler)
/* @endcond */

